#include "treenode.h"
#include <string.h>
#include <stdarg.h>
#include <assert.h>

const TreeNodeType treeNodeType;

TreeNode* TreeNode_new(
	int token, char* text, int isDynamic, int start, 
	int end, int col, int line)
{
	TreeNode* tn = (TreeNode*)malloc(sizeof(TreeNode));
	return TreeNode_init(tn, token, text, isDynamic, start, end, col, line);
}

TreeNode* TreeNode_new2(int token)
{
	TreeNode* tn = (TreeNode*)malloc(sizeof(TreeNode));
	return TreeNode_init2(tn, token);
}

TreeNode* TreeNode_init2(TreeNode* self, int token)
{
	TreeNode_init(self, token, NULL, 0, 0, 0, 0, 0);
	return self;
}

TreeNode* TreeNode_init(
	TreeNode* self, int token, char* text, int isDynamic, 
	int start, int end, int col, int line)
{
	self->token = token;
	self->bools.isDynamic = isDynamic;
	self->bools.isTerminal = 1;
	self->pos.start = start;
	self->pos.end = end;
	self->pos.col = col;
	self->pos.line = line;
	if (isDynamic) { self->text = _strdup(text); }
	else { self->text = text; }
	self->firstChild = NULL;
	self->nextSibling = NULL;
	self->type = &treeNodeType;
	return self;
}

void TreeNode_addChild(TreeNode* self, TreeNode* child)
{
	TreeNode* tn = self->firstChild;

	if (tn == NULL)
	{
		self->pos = child->pos;
		self->firstChild = child;
	} 
	else
	{
		while (tn->nextSibling != NULL)
		{
			self->pos.end = child->pos.end;
			tn = tn->nextSibling;
		}
		tn->nextSibling = child;
	}
}

static void vaAddChild(TreeNode* parent, va_list ap)
{
	TreeNode* child = va_arg(ap, TreeNode*);

	while (child != NULL)
	{
		TreeNode_addChild(parent, child);
		child = va_arg(ap, TreeNode*);
	}
}

void TreeNode_addChildren(TreeNode* self, ...)
{
	va_list ap;
	va_start(ap, self);
	vaAddChild(self, ap);
	va_end(ap);
}

TreeNode* TreeNode_new3(int token, ...)
{
	TreeNode* self;
	va_list ap;
	self = TreeNode_new2(token);
	va_start(ap, token);
	vaAddChild(self, ap);
	va_end(ap);
	return self;
}

void TreeNode_delete(TreeNode* self) 
{
	TreeNode* tn = self->firstChild;

	if (tn == NULL)
	{
		free(self);
	}
	else
	{
		while (tn != NULL)
		{
			TreeNode_delete(tn);
			tn = tn->nextSibling;
		}
		free(self);
	}
}